home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint108s.zoo / unifs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-27  |  18.2 KB  |  778 lines

  1. /*
  2. Copyright 1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5.  */
  6.  
  7. /* a simple unified file system */
  8.  
  9. #include "mint.h"
  10.  
  11.  
  12. extern FILESYS bios_filesys, proc_filesys, pipe_filesys, shm_filesys;
  13.  
  14. static long    ARGS_ON_STACK uni_root    P_((int drv, fcookie *fc));
  15. static long    ARGS_ON_STACK uni_lookup    P_((fcookie *dir, const char *name, fcookie *fc));
  16. static long    ARGS_ON_STACK uni_getxattr    P_((fcookie *fc, XATTR *xattr));
  17. static long    ARGS_ON_STACK uni_chattr    P_((fcookie *fc, int attrib));
  18. static long    ARGS_ON_STACK uni_chown    P_((fcookie *fc, int uid, int gid));
  19. static long    ARGS_ON_STACK uni_chmode    P_((fcookie *fc, unsigned mode));
  20. static long    ARGS_ON_STACK uni_rmdir    P_((fcookie *dir, const char *name));
  21. static long    ARGS_ON_STACK uni_remove    P_((fcookie *dir, const char *name));
  22. static long    ARGS_ON_STACK uni_getname    P_((fcookie *root, fcookie *dir,
  23.                             char *pathname, int size));
  24. static long    ARGS_ON_STACK uni_rename    P_((fcookie *olddir, char *oldname,
  25.                     fcookie *newdir, const char *newname));
  26. static long    ARGS_ON_STACK uni_opendir    P_((DIR *dirh, int flags));
  27. static long    ARGS_ON_STACK uni_readdir    P_((DIR *dirh, char *nm, int nmlen, fcookie *));
  28. static long    ARGS_ON_STACK uni_rewinddir    P_((DIR *dirh));
  29. static long    ARGS_ON_STACK uni_closedir    P_((DIR *dirh));
  30. static long    ARGS_ON_STACK uni_pathconf    P_((fcookie *dir, int which));
  31. static long    ARGS_ON_STACK uni_dfree    P_((fcookie *dir, long *buf));
  32. static DEVDRV *    ARGS_ON_STACK uni_getdev    P_((fcookie *fc, long *devsp));
  33. static long    ARGS_ON_STACK uni_symlink    P_((fcookie *dir, const char *name, const char *to));
  34. static long    ARGS_ON_STACK uni_readlink    P_((fcookie *fc, char *buf, int buflen));
  35. static long    ARGS_ON_STACK uni_fscntl    P_((fcookie *dir, const char *name, int cmd, long arg));
  36.  
  37. FILESYS uni_filesys = {
  38.     (FILESYS *)0,
  39.     FS_LONGPATH,
  40.     uni_root,
  41.     uni_lookup, nocreat, uni_getdev, uni_getxattr,
  42.     uni_chattr, uni_chown, uni_chmode,
  43.     nomkdir, uni_rmdir, uni_remove, uni_getname, uni_rename,
  44.     uni_opendir, uni_readdir, uni_rewinddir, uni_closedir,
  45.     uni_pathconf, uni_dfree, nowritelabel, noreadlabel,
  46.     uni_symlink, uni_readlink, nohardlink, uni_fscntl, nodskchng
  47. };
  48.  
  49. /*
  50.  * structure that holds files
  51.  * if (mode & S_IFMT == S_IFDIR), then this is an alias for a drive:
  52.  *    "dev" holds the appropriate BIOS device number, and
  53.  *    "data" is meaningless
  54.  * if (mode & S_IFMT == S_IFLNK), then this is a symbolic link:
  55.  *    "dev" holds the user id of the owner, and
  56.  *    "data" points to the actual link data
  57.  */
  58.  
  59. typedef struct unifile {
  60.     char name[NAME_MAX+1];
  61.     ushort mode;
  62.     ushort dev;
  63.     FILESYS *fs;
  64.     void *data;
  65.     struct unifile *next;
  66. } UNIFILE;
  67.  
  68. static UNIFILE u_drvs[UNI_NUM_DRVS];
  69. static UNIFILE *u_root = 0;
  70.  
  71. void
  72. unifs_init()
  73. {
  74.     UNIFILE *u = u_drvs;
  75.     int i;
  76.  
  77.     u_root = u;
  78.     for (i = 0; i < UNI_NUM_DRVS; i++,u++) {
  79.         u->next = u+1;
  80.         u->mode = S_IFDIR|DEFAULT_DIRMODE;
  81.         u->dev = i;
  82.         if (i == PROCDRV) {
  83.             strcpy(u->name, "proc");
  84.             u->fs = &proc_filesys;
  85.         } else if (i == PIPEDRV) {
  86.             strcpy(u->name, "pipe");
  87.             u->fs = &pipe_filesys;
  88.         } else if (i == BIOSDRV) {
  89.             strcpy(u->name, "dev");
  90.             u->fs = &bios_filesys;
  91.         } else if (i == UNIDRV) {
  92.             (u-1)->next = u->next;    /* skip this drive */
  93.         } else if (i == SHMDRV) {
  94.             strcpy(u->name, "shm");
  95.             u->fs = &shm_filesys;
  96.         } else {
  97.             u->name[0] = i + 'a';
  98.             u->name[1] = 0;
  99.             u->fs = 0;
  100.         }
  101.     }
  102.     --u;    /* oops, we went too far */
  103.     u->next = 0;
  104. }
  105.  
  106. static long ARGS_ON_STACK 
  107. uni_root(drv, fc)
  108.     int drv;
  109.     fcookie *fc;
  110. {
  111.     if (drv == UNIDRV) {
  112.         fc->fs = &uni_filesys;
  113.         fc->dev = drv;
  114.         fc->index = 0L;
  115.         return 0;
  116.     }
  117.     fc->fs = 0;
  118.     return EINTRN;
  119. }
  120.  
  121. static long ARGS_ON_STACK 
  122. uni_lookup(dir, name, fc)
  123.     fcookie *dir;
  124.     const char *name;
  125.     fcookie *fc;
  126. {
  127.     UNIFILE *u;
  128.     long drvs;
  129.     FILESYS *fs;
  130.     fcookie *tmp;
  131.     extern long dosdrvs;
  132.  
  133.     TRACE(("uni_lookup(%s)", name));
  134.  
  135.     if (dir->index != 0) {
  136.         DEBUG(("uni_lookup: bad directory"));
  137.         return EPTHNF;
  138.     }
  139. /* special case: an empty name in a directory means that directory */
  140. /* so do "." and ".." */
  141.  
  142.     if (!*name || !strcmp(name, ".") || !strcmp(name, "..")) {
  143.         dup_cookie(fc, dir);
  144.         return 0;
  145.     }
  146.     drvs = drvmap() | dosdrvs | PSEUDODRVS;
  147. /*
  148.  * OK, check the list of aliases and special directories
  149.  */
  150.     for (u = u_root; u; u = u->next) {
  151.         if (!stricmp(name, u->name)) {
  152.             if ( (u->mode & S_IFMT) == S_IFDIR ) {
  153.                 if (u->dev >= NUM_DRIVES) {
  154.                     fs = u->fs;
  155.                     return (*fs->root)(u->dev,fc);
  156.                 }
  157.                 if ((drvs & (1L << u->dev)) == 0)
  158.                     return EPTHNF;
  159.                 tmp = &curproc->root[u->dev];
  160.                 if (!tmp->fs) {        /* drive changed? */
  161.                     changedrv(tmp->dev);
  162.                     tmp = &curproc->root[u->dev];
  163.                     if (!tmp->fs)
  164.                         return EPTHNF;
  165.                 }
  166.                 dup_cookie(fc, tmp);
  167.             } else {        /* a symbolic link */
  168.                 fc->fs = &uni_filesys;
  169.                 fc->dev = UNIDRV;
  170.                 fc->index = (long)u;
  171.             }
  172.             return 0;
  173.         }
  174.     }
  175.     DEBUG(("uni_lookup: name (%s) not found", name));
  176.     return EFILNF;
  177. }
  178.  
  179. static long ARGS_ON_STACK 
  180. uni_getxattr(fc, xattr)
  181.     fcookie *fc;
  182.     XATTR *xattr;
  183. {
  184.     UNIFILE *u = (UNIFILE *)fc->index;
  185.  
  186.     if (fc->fs != &uni_filesys) {
  187.         ALERT("ERROR: wrong file system getxattr called");
  188.         return EINTRN;
  189.     }
  190.  
  191.     xattr->index = fc->index;
  192.     xattr->dev = fc->dev;
  193.     xattr->nlink = 1;
  194.     xattr->blksize = 1;
  195.  
  196. /* If "u" is null, then we have the root directory, otherwise
  197.  * we use the UNIFILE structure to get the info about it
  198.  */
  199.     if (!u || ( (u->mode & S_IFMT) == S_IFDIR )) {
  200.         xattr->uid = xattr->gid = 0;
  201.         xattr->size = xattr->nblocks = 0;
  202.         xattr->mode = S_IFDIR | DEFAULT_DIRMODE;
  203.         xattr->attr = FA_DIR;
  204.     } else {
  205.         xattr->uid = u->dev;
  206.         xattr->gid = 0;
  207.         xattr->size = xattr->nblocks = strlen(u->data) + 1;
  208.         xattr->mode = u->mode;
  209.         xattr->attr = 0;
  210.     }
  211.     xattr->mtime = xattr->atime = xattr->ctime = 0;
  212.     xattr->mdate = xattr->adate = xattr->cdate = 0;
  213.     return 0;
  214. }
  215.  
  216. static long ARGS_ON_STACK 
  217. uni_chattr(dir, attrib)
  218.     fcookie *dir;
  219.     int attrib;
  220. {
  221.     UNUSED(dir); UNUSED(attrib);
  222.     return EACCDN;
  223. }
  224.  
  225. static long ARGS_ON_STACK 
  226. uni_chown(dir, uid, gid)
  227.     fcookie *dir;
  228.     int uid, gid;
  229. {
  230.     UNUSED(dir); UNUSED(uid);
  231.     UNUSED(gid);
  232.     return EINVFN;
  233. }
  234.  
  235. static long ARGS_ON_STACK 
  236. uni_chmode(dir, mode)
  237.     fcookie *dir;
  238.     unsigned mode;
  239. {
  240.     UNUSED(dir);
  241.     UNUSED(mode);
  242.     return EINVFN;
  243. }
  244.  
  245. static long ARGS_ON_STACK 
  246. uni_rmdir(dir, name)
  247.     fcookie *dir;
  248.     const char *name;
  249. {
  250.     long r;
  251.  
  252.     r = uni_remove(dir, name);
  253.     if (r == EFILNF) r = EPTHNF;
  254.     return r;
  255. }
  256.  
  257. static long ARGS_ON_STACK 
  258. uni_remove(dir, name)
  259.     fcookie *dir;
  260.     const char *name;
  261. {
  262.     UNIFILE *u, *lastu;
  263.  
  264.     UNUSED(dir);
  265.  
  266.     lastu = 0;
  267.     u = u_root;
  268.     while (u) {
  269.         if (!strncmp(u->name, name, NAME_MAX)) {
  270.             if ( (u->mode & S_IFMT) != S_IFLNK ) return EFILNF;
  271.             kfree(u->data);
  272.             if (lastu)
  273.                 lastu->next = u->next;
  274.             else
  275.                 u_root = u->next;
  276.             kfree(u);
  277.             return 0;
  278.         }
  279.         lastu = u;
  280.         u = u->next;
  281.     }
  282.     return EFILNF;
  283. }
  284.  
  285. static long ARGS_ON_STACK 
  286. uni_getname(root, dir, pathname, size)
  287.     fcookie *root, *dir; char *pathname;
  288.     int size;
  289. {
  290.     FILESYS *fs;
  291.     UNIFILE *u;
  292.     char *n;
  293.     fcookie relto;
  294.     char tmppath[PATH_MAX];
  295.     long r;
  296.  
  297.     UNUSED(root);
  298.  
  299.     if (size <= 0) return ERANGE;
  300.  
  301.     fs = dir->fs;
  302.     if (dir->dev == UNIDRV) {
  303.         *pathname = 0;
  304.         return 0;
  305.     }
  306.  
  307.     for (u = u_root; u; u = u->next) {
  308.         if (dir->dev == u->dev && (u->mode & S_IFMT) == S_IFDIR) {
  309.             *pathname++ = '\\';
  310.             if (--size <= 0) return ERANGE;
  311.             for (n = u->name; *n; ) {
  312.                 *pathname++ = *n++;
  313.                 if (--size <= 0) return ERANGE;
  314.             }
  315.             break;
  316.         }
  317.     }
  318.  
  319.     if (!u) {
  320.         ALERT("unifs: couldn't match a drive with a directory");
  321.         return EPTHNF;
  322.     }
  323.  
  324.     if (dir->dev >= NUM_DRIVES) {
  325.         if ((*fs->root)(dir->dev, &relto) == 0) {
  326.             if (!(fs->fsflags & FS_LONGPATH)) {
  327.                 r = (*fs->getname)(&relto, dir, tmppath, PATH_MAX);
  328.                 release_cookie(&relto);
  329.                 if (r) {
  330.                     return r;
  331.                 }
  332.                 if (strlen(tmppath) < size) {
  333.                     strcpy(pathname, tmppath);
  334.                     return 0;
  335.                 } else {
  336.                     return ERANGE;
  337.                 }
  338.             }
  339.             r = (*fs->getname)(&relto, dir, pathname, size);
  340.             release_cookie(&relto);
  341.             return r;
  342.         } else {
  343.             *pathname = 0;
  344.             return EINTRN;
  345.         }
  346.     }
  347.  
  348.     if (curproc->root[dir->dev].fs != fs) {
  349.         ALERT("unifs: drive's file system doesn't match directory's");
  350.         return EINTRN;
  351.     }
  352.  
  353.     if (!(fs->fsflags & FS_LONGPATH)) {
  354.         r = (*fs->getname)(&curproc->root[dir->dev], dir, tmppath, PATH_MAX);
  355.         if (r) return r;
  356.         if (strlen(tmppath) < size) {
  357.             strcpy(pathname, tmppath);
  358.             return 0;
  359.         } else {
  360.             return ERANGE;
  361.         }
  362.     }
  363.     return (*fs->getname)(&curproc->root[dir->dev], dir, pathname, size);
  364. }
  365.  
  366. static long ARGS_ON_STACK 
  367. uni_rename(olddir, oldname, newdir, newname)
  368.     fcookie *olddir;
  369.     char *oldname;
  370.     fcookie *newdir;
  371.     const char *newname;
  372. {
  373.     UNIFILE *u;
  374.     fcookie fc;
  375.     long r;
  376.  
  377.     UNUSED(olddir);
  378.  
  379.     for (u = u_root; u; u = u->next) {
  380.         if (!stricmp(u->name, oldname))
  381.             break;
  382.     }
  383.  
  384.     if (!u) {
  385.         DEBUG(("uni_rename: old file not found"));
  386.         return EFILNF;
  387.     }
  388.  
  389. /* the new name is not allowed to exist! */
  390.     r = uni_lookup(newdir, newname, &fc);
  391.     if (r == 0)
  392.         release_cookie(&fc);
  393.  
  394.     if (r != EFILNF) {
  395.         DEBUG(("uni_rename: error %ld", r));
  396.         return (r == 0) ? EACCDN : r;
  397.     }
  398.  
  399.     (void)strncpy(u->name, newname, NAME_MAX);
  400.     return 0;
  401. }
  402.  
  403. static long ARGS_ON_STACK 
  404. uni_opendir(dirh, flags)
  405.     DIR *dirh;
  406.     int flags;
  407. {
  408.     UNUSED(flags);
  409.  
  410.     if (dirh->fc.index != 0) {
  411.         DEBUG(("uni_opendir: bad directory"));
  412.         return EPTHNF;
  413.     }
  414.     dirh->index = 0;
  415.     return 0;
  416. }
  417.  
  418.  
  419. static long ARGS_ON_STACK 
  420. uni_readdir(dirh, name, namelen, fc)
  421.     DIR *dirh;
  422.     char *name;
  423.     int namelen;
  424.     fcookie *fc;
  425. {
  426.     long map;
  427.     char *dirname;
  428.     int i;
  429.     int giveindex = (dirh->flags == 0);
  430.     UNIFILE *u;
  431.     long index;
  432.     extern long dosdrvs;
  433.     long r;
  434.  
  435.     map = dosdrvs | drvmap() | PSEUDODRVS;
  436.     i = dirh->index++;
  437.     u = u_root;
  438.     while (i > 0) {
  439.         --i;
  440.         u = u->next;
  441.         if (!u)
  442.             break;
  443.     }
  444. tryagain:
  445.     if (!u) return ENMFIL;
  446.  
  447.     dirname = u->name;
  448.     index = (long)u;
  449.     if ( (u->mode & S_IFMT) == S_IFDIR ) {
  450. /* make sure the drive really exists */
  451.         if ( u->dev >= NUM_DRIVES) {
  452.             r = (*u->fs->root)(u->dev,fc);
  453.             if (r) {
  454.             fc->fs = &uni_filesys;
  455.             fc->index = 0;
  456.             fc->dev = u->dev;
  457.             }
  458.         } else {
  459.             if ((map & (1L << u->dev)) == 0 ) {
  460.             dirh->index++;
  461.             u = u->next;
  462.             goto tryagain;
  463.             }
  464.             dup_cookie(fc, &curproc->root[u->dev]);
  465.             if (!fc->fs) {    /* drive not yet initialized */
  466.         /* use default attributes */
  467.             fc->fs = &uni_filesys;
  468.             fc->index = 0;
  469.             fc->dev = u->dev;
  470.             }
  471.         }
  472.     } else {        /* a symbolic link */
  473.         fc->fs = &uni_filesys;
  474.         fc->dev = UNIDRV;
  475.         fc->index = (long)u;
  476.     }
  477.  
  478.     if (giveindex) {
  479.         namelen -= (int)sizeof(long);
  480.         if (namelen <= 0) {
  481.             release_cookie(fc);
  482.             return ERANGE;
  483.         }
  484.         *((long *)name) = index;
  485.         name += sizeof(long);
  486.     }
  487.     strncpy(name, dirname, namelen-1);
  488.     if (strlen(name) < strlen(dirname)) {
  489.         release_cookie(fc);
  490.         return ENAMETOOLONG;
  491.     }
  492.     return 0;
  493. }
  494.  
  495. static long ARGS_ON_STACK 
  496. uni_rewinddir(dirh)
  497.     DIR *dirh;
  498. {
  499.     dirh->index = 0;
  500.     return 0;
  501. }
  502.  
  503. static long ARGS_ON_STACK 
  504. uni_closedir(dirh)
  505.     DIR *dirh;
  506. {
  507.     UNUSED(dirh);
  508.     return 0;
  509. }
  510.  
  511. static long ARGS_ON_STACK 
  512. uni_pathconf(dir, which)
  513.     fcookie *dir;
  514.     int which;
  515. {
  516.     UNUSED(dir);
  517.  
  518.     switch(which) {
  519.     case -1:
  520.         return DP_MAXREQ;
  521.     case DP_IOPEN:
  522.         return 0;        /* no files to open */
  523.     case DP_MAXLINKS:
  524.         return 1;        /* no hard links available */
  525.     case DP_PATHMAX:
  526.         return PATH_MAX;
  527.     case DP_NAMEMAX:
  528.         return NAME_MAX;
  529.     case DP_ATOMIC:
  530.         return 1;        /* no atomic writes */
  531.     case DP_TRUNC:
  532.         return DP_AUTOTRUNC;
  533.     case DP_CASE:
  534.         return DP_CASEINSENS;
  535.     default:
  536.         return EINVFN;
  537.     }
  538. }
  539.  
  540. static long ARGS_ON_STACK 
  541. uni_dfree(dir, buf)
  542.     fcookie *dir;
  543.     long *buf;
  544. {
  545.     UNUSED(dir);
  546.  
  547.     buf[0] = 0;    /* number of free clusters */
  548.     buf[1] = 0;    /* total number of clusters */
  549.     buf[2] = 1;    /* sector size (bytes) */
  550.     buf[3] = 1;    /* cluster size (sectors) */
  551.     return 0;
  552. }
  553.  
  554. static DEVDRV * ARGS_ON_STACK 
  555. uni_getdev(fc, devsp)
  556.     fcookie *fc;
  557.     long *devsp;
  558. {
  559.     UNUSED(fc);
  560.  
  561.     *devsp = EACCDN;
  562.     return 0;
  563. }
  564.  
  565. static long ARGS_ON_STACK 
  566. uni_symlink(dir, name, to)
  567.     fcookie *dir;
  568.     const char *name;
  569.     const char *to;
  570. {
  571.     UNIFILE *u;
  572.     fcookie fc;
  573.     long r;
  574.  
  575.     r = uni_lookup(dir, name, &fc);
  576.     if (r == 0) {
  577.         release_cookie(&fc);
  578.         return EACCDN;    /* file already exists */
  579.     }
  580.     if (r != EFILNF) return r;    /* some other error */
  581.  
  582.     u = kmalloc(SIZEOF(UNIFILE));
  583.     if (!u) return EACCDN;
  584.  
  585.     strncpy(u->name, name, NAME_MAX);
  586.     u->name[NAME_MAX] = 0;
  587.  
  588.     u->data = kmalloc((long)strlen(to)+1);
  589.     if (!u->data) {
  590.         kfree(u);
  591.         return EACCDN;
  592.     }
  593.     strcpy(u->data, to);
  594.     u->mode = S_IFLNK | DEFAULT_DIRMODE;
  595.     u->dev = curproc->ruid;
  596.     u->next = u_root;
  597.     u->fs = &uni_filesys;
  598.     u_root = u;
  599.     return 0;
  600. }
  601.  
  602. static long ARGS_ON_STACK 
  603. uni_readlink(fc, buf, buflen)
  604.     fcookie *fc;
  605.     char *buf;
  606.     int buflen;
  607. {
  608.     UNIFILE *u;
  609.  
  610.     u = (UNIFILE *)fc->index;
  611.     assert(u);
  612.     assert((u->mode & S_IFMT) == S_IFLNK);
  613.     assert(u->data);
  614.     strncpy(buf, u->data, buflen);
  615.     if (strlen(u->data) >= buflen)
  616.         return ENAMETOOLONG;
  617.     return 0;
  618. }
  619.  
  620.  
  621.  
  622.  
  623. /* uk: use these Dcntl's to install a new filesystem which is only visible
  624.  *     on drive u:
  625.  *
  626.  *     FS_INSTALL:   let the kernel know about the file system; it does NOT
  627.  *                   get a device number.
  628.  *     FS_MOUNT:     use Dcntl(FS_MOUNT, "u:\\foo", &descr) to make a directory
  629.  *                   foo where the filesytem resides in; the file system now
  630.  *                   gets its device number which is also written into the
  631.  *                   dev_no field of the fs_descr structure.
  632.  *     FS_UNMOUNT:   remove a file system's directory; this call closes all
  633.  *                   open files, directory searches and directories on this
  634.  *                   device. Make sure that the FS will not recognise any
  635.  *                   accesses to this device, as fs->root will be called
  636.  *                   during the reinitalisation!
  637.  *     FS_UNINSTALL: remove a file system completely from the kernel list,
  638.  *                   but that will only be possible if there is no directory
  639.  *                   associated with this file system.
  640.  *                   This function allows it to write file systems as demons
  641.  *                   which stay in memory only as long as needed.
  642.  *
  643.  * BUG: it is not possible yet to lock such a filesystem.
  644.  */
  645.  
  646. /* here we start with gemdos only file system device numbers */
  647. static curr_dev_no = 0x100;
  648.  
  649.  
  650.  
  651. static long ARGS_ON_STACK
  652. uni_fscntl(dir, name, cmd, arg)
  653.     fcookie *dir;
  654.     const char *name;
  655.     int cmd;
  656.     long arg;
  657. {
  658.     fcookie fc;
  659.     long r;
  660.  
  661.     extern struct kerinfo kernelinfo;
  662.     extern FILESYS *active_fs;
  663.  
  664.     if (cmd == FS_INSTALL) { /* install a new filesystem */
  665.         struct fs_descr *d = (struct fs_descr*)arg;
  666.         FILESYS *fs;
  667.  
  668.     /* check if FS is installed already */
  669.         for (fs = active_fs;  fs;  fs = fs->next)
  670.             if (d->file_system == fs)  return 0L;
  671.     /* include new file system into chain of file systems */
  672.         d->file_system->next = active_fs;
  673.         active_fs = d->file_system;
  674.         return (long)&kernelinfo;  /* return pointer to kernel info as OK */
  675.     } else if (cmd == FS_MOUNT) {  /* install a new gemdos-only device for this FS */
  676.         struct fs_descr *d = (struct fs_descr*)arg;
  677.         FILESYS *fs;
  678.         UNIFILE *u;
  679.  
  680.     /* first check for existing names */
  681.         r = uni_lookup(dir, name, &fc);
  682.         if (r == 0) {
  683.             release_cookie(&fc);
  684.             return EACCDN;   /* name exists already */
  685.         }
  686.         if (r != EFILNF) return r; /* some other error */
  687.         if (!d) return EACCDN;
  688.         if (!d->file_system) return EACCDN;
  689.     /* check if FS is installed */
  690.         for (fs = active_fs;  fs;  fs = fs->next)
  691.             if (d->file_system == fs)  break;
  692.         if (!fs) return EACCDN;  /* not installed, so return an error */
  693.         u = kmalloc(SIZEOF(UNIFILE));
  694.         if (!u) return EACCDN;
  695.         strncpy(u->name, name, NAME_MAX);
  696.         u->name[NAME_MAX] = 0;
  697.         u->mode = S_IFDIR|DEFAULT_DIRMODE;
  698.         u->data = 0;
  699.         u->fs = d->file_system;
  700.     /* now get the file system its own device number */
  701.         u->dev = d->dev_no = curr_dev_no++;
  702.     /* chain new entry into unifile list */
  703.         u->next = u_root;
  704.         u_root = u;
  705.         return (long)u->dev;
  706.     } else if (cmd == FS_UNMOUNT) {  /* remove a file system's directory */
  707.         struct fs_descr *d = (struct fs_descr*)arg;
  708.         FILESYS *fs;
  709.         UNIFILE *u;
  710.  
  711.     /* first check that directory exists */
  712.         r = uni_lookup(dir, name, &fc);
  713.         if (r != 0)  return EFILNF;   /* name does not exist */
  714.         if (!d) return EFILNF;
  715.         if (!d->file_system) return EFILNF;
  716.         if (d->file_system != fc.fs)
  717.             return EFILNF;  /* not the right name! */
  718.         u = (UNIFILE*)fc.index;
  719.         release_cookie(&fc);
  720.         if (!u || (u->fs != d->file_system))
  721.             return EFILNF;
  722.     /* check if FS is installed */
  723.         for (fs = active_fs;  fs;  fs = fs->next)
  724.             if (d->file_system == fs)  break;
  725.         if (!fs) return EACCDN;  /* not installed, so return an error */
  726.  
  727.     /* here comes the difficult part: we have to close all files on that
  728.      * device, so we have to call changedrv(). The file system driver
  729.      * has to make sure that further calls to fs.root() with this device
  730.      * number will fail!
  731.      *
  732.      * Kludge: mark the directory as a link, so uni_remove will remove it.
  733.      */
  734.         changedrv(u->dev);
  735.         u->mode &= ~S_IFMT;
  736.         u->mode |= S_IFLNK;
  737.         return uni_remove(dir, name);
  738.     } else if (cmd == FS_UNINSTALL) {    /* remove file system from kernel list */
  739.         struct fs_descr *d = (struct fs_descr*)arg;
  740.         FILESYS *fs, *last_fs;
  741.         UNIFILE *u;
  742.  
  743.     /* first check if there are any files or directories associated with
  744.      * this file system
  745.      */
  746.         for (u = u_root;  u;  u = u->next)
  747.             if (u->fs == d->file_system)
  748.                 return EACCDN;   /* we cannot remove it before unmount */
  749.         last_fs = 0;
  750.         fs = active_fs;
  751.         while (fs)  {   /* go through the list and remove the file system */
  752.             if (fs == d->file_system)  {
  753.                 if (last_fs)
  754.                     last_fs->next = fs->next;
  755.                 else
  756.                     active_fs = fs->next;
  757.                 d->file_system->next = 0;
  758.                 return 0;
  759.             }
  760.             last_fs = fs;
  761.             fs = fs->next;
  762.         }
  763.         return EFILNF;
  764.     } else {
  765.     /* see if we should just pass this along to another file system */
  766.         r = uni_lookup(dir, name, &fc);
  767.         if (r == 0) {
  768.             if (fc.fs != &uni_filesys) {
  769.                 r = (*fc.fs->fscntl)(&fc, ".", cmd, arg);
  770.                 release_cookie(&fc);
  771.                 return r;
  772.             }
  773.             release_cookie(&fc);
  774.         }
  775.     }
  776.     return EINVFN;
  777. }
  778.